iT邦幫忙

2023 iThome 鐵人賽

DAY 22
1
Vue.js

Vue3歡樂套件箱耶系列 第 22

開箱22:效能優化?記憶化(Memoization)~Vue範例應用

  • 分享至 

  • xImage
  •  

在前端開發中,記憶化(Memoization)主要用於優化性能,特別是在需要頻繁計算或重新渲染的情況下。所以我們今天來認識一下在Vue中,有幾種方式可以實現Memoization

目錄

  • 介紹 記憶化
  • 什麼時候才需要用記憶化
  • Vue Memoization Example
    -使用 computed
    -使用 v-memo
    -使用第三方套件
  • 延伸閱讀

記憶化(Memoization)

記憶化是一種特定於算法和程式設計的優化技術。它用於儲存函數呼叫的結果,所以當同一個輸入再次出現時,可以直接從記憶儲存區取出結果,而不需要重新計算。

優點:
提高算法效能,特別是對於遞迴函數。
減少不必要的計算。

缺點:
會消耗額外的記憶體來儲存結果。
需要確保函數是「純函數(Pure Function)」,也就是相同的輸入必須產生相同的輸出。

什麼時候才需要用記憶化?

記憶化(Memoization)是一種優化手段,不是所有情況都適用。以下是一些可能需要使用記憶化的情境:

  • 高計算成本的函數
    如果你有一個計算成本非常高的函數,並且會被多次呼叫,特別是與相同的參數,那麼使用記憶化可以減少不必要的計算。
  • 遞迴函數
    遞迴函數,特別是那些有重複計算的(例如費波納契數列),是記憶化的經典應用場景。
  • 頻繁重新渲染的 UI 組件
    在前端框架(如 React)中,如果有一個組件會因為父組件的重新渲染而頻繁地重新渲染,即使它的 props 沒有改變,那麼你可能會想使用 React.memo 或 useMemo。
  • 資料過濾和排序
    如果你的應用需要對大量資料進行過濾或排序,並且這些操作是經常發生的,那麼記憶化過濾和排序函數的結果可能會是有用的。
  • 網絡請求
    如果你的應用需要發送相同的網絡請求多次,並且確保數據在短時間內不會變化,則可以使用記憶化來儲存請求結果。

Vue Memoization Example

在Vue中,有幾種方式可以實現Memoization

  1. 使用 computed 屬性
    Vue 的 computed 屬性本身就是一種形式的記憶化。當它們的依賴變量沒有變化時,它們會返回緩存的結果,而不會重新計算。
// vue3 Option Api寫法
computed: {
  computedValue() {
    // 進行一些昂貴的計算
    return expensiveCalculation(this.someData);
  }
}
// Vue3 Composition Api寫法
const computedValue = computed(()=>{ return expensiveCalculation(someData)})
  1. 使用 v-memo 指令(Vue 3.2+)
    Vue 3.2+版本引入了一個新的 v-memo 指令,用於條件性地跳過元素和組件的渲染。能微小的效能優化
    類型:any[]

詳細可看官方文件 v-memo

這邊舉例一個搭配 v-for 簡單範例

▼ 在這個例子中,v-memo接受[],其中條件是item.id === selected。
v-memo用在這裡本質上是在說「只有當該項的被選中狀態改變時才需要更新」

<template>
  <div>
    <!-- 按鈕用於改變選中的項目 -->
    <button @click="selectItem(1)">選擇項目 1</button>
    <button @click="selectItem(2)">選擇項目 2</button>
    <button @click="selectItem(3)">選擇項目 3</button>
    
    <!-- 列表渲染 -->
    <ul>
      <li v-for="item in list" :key="item.id" v-memo="[item.id === selected]">
        <p>ID: {{ item.id }}</span> - <span>選中: {{ item.id === selected }}</p>
        <p>{{ logRender(item.id) }}</p> // 測試是否渲染
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref } from 'vue';

// 列表數據
const list = [
  { id: 1, name: '項目 1' },
  { id: 2, name: '項目 2' },
  { id: 3, name: '項目 3' }
];

// 當前選中的項目 ID
const selected = ref(null);

// 函數用於改變選中的項目
const selectItem = (id) => {
  selected.value = id;
};

// 用來測試是否渲染
const logRender = id => {
  console.log(`Rendering item with ID: ${id}`);
  return `Rendering item with ID: ${id}`;
};

</script>

當搭配v-for使用v-memo,確保兩者都綁定在同一個元素上。v-memo不能用在v-for內部。


使用v-memo vs 沒有使用 成果比較

功能大綱:先選擇2 > 在選擇1
Demo網址:https://hahasister-ironman-project.netlify.app/#/vmemo

  • 使用v-memo

    先選擇2,只有 ID 為 2的項目會被重新渲染,而其他項目則會保持不會
    再選擇1,ID 為 2 和 3 的項目有變動才會被重新渲染

  • 沒有用v-memo
    不管是哪個選擇改變了,所有的項目都會被重新渲染

  <li v-for="item in list" :key="item.id">
      ....
  </li>

官方舉例是當v-for列表(長度超過1000 的情況),在處理大量數據或複雜操作時,使用 v-memo 的性能優勢會更為明顯

  1. 使用第三方套件 例如:useMemoize
  • useMemoize 是 VueUse 函式庫中的一個功能,用於緩存函數的結果,並根據參數保持其響應性。

官方介紹 https://vueuse.org/core/useMemoize/

用途

  • 緩存函數的結果,以減少不必要的計算或網絡請求。
  • 可用於同步或異步函數。
  • 避免在同一時間內獲取相同的數據。

清除緩存

  • 緩存的結果不會自動清除。如果你不再需要結果,可以調用 clear() 方法。
getUser.clear()  // 清除全部緩存

簡單範例

功能大綱

  • 點擊按鈕可以獲得數據(如果獲得數據一樣,則不會重新請求)
  • 實現每次獲得數據一樣來測試,是使用

JSONPlaceholder: 一個免費的線上 REST API,你可以用它來獲取假數據。
網址:JSONPlaceholder
例如,https://jsonplaceholder.typicode.com/todos/1 能總是返回相同的待辦事項。

<template>
...
    <div class="flex mt-4">
      <button @click="getData(1)">獲取數據1</button>
      <button @click="getData(2)">獲取數據2</button>
    </div>

    <div class="mt-4">
      {{ data }}
    </div>
...
</template>
<script setup>
import { ref } from 'vue';
import { useMemoize } from '@vueuse/core';
import axios from 'axios';

const data = ref(null);

const getUseMemoizeData = useMemoize(async id => {
  const url = `https://jsonplaceholder.typicode.com/todos/${id}`;
  const { data } = await axios.get(url);
  return data;
});

const getData = async id => {
  await getUseMemoizeData(id).then(res => {
    data.value = res;
  });
};
</script>

實務上我們可能會多次請求數據,如果請求數據資料都一樣的話,可以緩存就可以減少請求,所以我們來看看使用useMemoize的成果

Demo網址:https://hahasister-ironman-project.netlify.app/#/useMemoize

▲ 試著點擊「獲取數據1」> 再按「獲取數據1」因為得來值的一樣,所以不會再次請求 >按「獲取數據2」因為獲得的值不同,所以會再次請求

當然你也可以自己寫程式手動實現...

延伸閱讀

[演算法] Fibonacci:善用 cache 和 Memoization 提升程式效能
What is Memoization? How and When to Memoize in JavaScript and React


那我們明天再見了~
/images/emoticon/emoticon30.gif


上一篇
開箱21:提示/彈出視窗元件輕鬆套!~Vue 3 Popper範例應用
下一篇
開箱23:Vue 3 + 建立web應用程式+Firebase JS SDK 初始化
系列文
Vue3歡樂套件箱耶30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言